package com.tushen;

import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconst;
import org.gdal.ogr.*;
import org.gdal.osr.SpatialReference;
import ucar.ma2.Array;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import com.tushen.utils.SqlSessionFactoryUtil;
import com.tushen.utils.Utils;

import java.sql.Time;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * NC 数据处理读取
 * create by likun on 2020/7/16 0016
 */
public class NCTask {



    public static void main(String[] args){

        String path="D:\\data\\nwp_cur_20190523.nc";
        String outPath="D:\\其他\\hesu\\nwp_nc\\nwp_nc_shp\\";
        path="/Users/likun/Downloads/nwp_cur_20190523.nc";
        if(args.length<1){
            System.out.println("please input path");
            return;
        }
        path=args[0];

        readNC(path);
       // processNC(path,outPath);
       // test();
    }

    public static void test(){

        DateTimeFormatter dateTimeFormatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime dtm=LocalDateTime.parse("2020-07-08 19:00:00",dateTimeFormatter);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = dtm.atZone(zoneId);//Combines this date-time with a time-zone to create a  ZonedDateTime.
        Date date = Date.from(zdt.toInstant());

        java.sql.Date dt=new java.sql.Date(date.getTime());
        Time tm=new java.sql.Time(date.getTime());
        System.out.println(dt.toString());
        System.out.println(tm.toString());
    }

    public static void readNC(String fileName){
        try {
            NetcdfFile netcdfFile=NetcdfFile.open(fileName);
            List<Dimension> dimensions = netcdfFile.getDimensions();
            for (Dimension dimension:dimensions){
                System.out.println(dimension.getFullName());
                System.out.println(dimension.getLength());
            }

            System.out.println();
            Variable lat = netcdfFile.findVariable("lat");
            Array lat_data=lat.read();

            lat = netcdfFile.findVariable("lon");
            Array lon_data=lat.read();

            // 0:左上角x坐标 1:东西方向空间分辨率 2:x方向旋转角0° 3:左上角y坐标 4:y方向旋转角0° 5:南北方向空间分辨率
            int size_lon=(int) lon_data.getSize();
            double start_lon=lon_data.getDouble(0);
            double end_lon=lon_data.getDouble(size_lon-1);
            double res_lon=(end_lon-start_lon)/(size_lon-1);

            System.out.println(res_lon);

            int size_lat=(int) lat_data.getSize();
            double start_lat=lat_data.getDouble(0);
            double end_lat=lat_data.getDouble(size_lat-1);
            double res_lat=(end_lat-start_lat)/(size_lat-1);

            System.out.println(res_lat);

            // 0:左上角x坐标 1:东西方向空间分辨率 2:x方向旋转角0° 3:左上角y坐标 4:y方向旋转角0° 5:南北方向空间分辨率
            double[] argin = {start_lon, res_lon, 0, start_lat, 0, res_lat};

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMMddHH");
            LocalDateTime startTime = LocalDateTime.of(1990, 1, 1, 0, 0, 0);
//            LocalDateTime startTime = LocalDateTime.of(1990, 1, 1, 8, 0, 0);

            Variable time=netcdfFile.findVariable("time");
            Variable u=netcdfFile.findVariable("u");
            Variable v=netcdfFile.findVariable("v");
            int[] shp={1,1,(int)lat_data.getSize(),(int)lon_data.getSize()};
            Array timeData=time.read();
            long start=System.currentTimeMillis();
            for (int i=0;i<timeData.getSize();i++){
                LocalDateTime dtm=startTime.plusHours(timeData.getLong(i));
                String fileNamePath="nwp_cur_"+ formatter.format(dtm) + ".tif";
                System.out.println(i+": "+fileNamePath+" finished");
//                System.out.println(i+": "+timeData.getLong(i));
                // break;
            }

            double div=(System.currentTimeMillis()-start)/1000.0;
            System.out.println("耗时:"+div+"秒");


//            int nlats = lat.getElementSize(); // number of latitudes
////            double [] lats = new double[nlats];	// where to put them
//            int[] index = new int[1]; // index array to specify which value
//            for (int ilat = 0; ilat < nlats; ilat++) {
//                index[0] = ilat;
////                lats[ilat] = lat.readScalarInt();
//            }
	    /* Read units attribute of lat variable */
//            String latUnits = lat.getAttribute("units").getStringValue();




            List<Variable> variables = netcdfFile.getVariables();

            for (Variable variable:variables){
                System.out.println(variable.getNameAndDimensions());
                List<Attribute> attributes=variable.getAttributes();
                System.out.println("attributes.size:"+attributes.size());
                for (Attribute attribute:attributes){
                    System.out.println(attribute.getStringValue());
                    System.out.println(attribute.getDataType());
                    System.out.println(attribute.getLength());
                    System.out.println();
                }
                List<Dimension> list=variable.getDimensions();
                System.out.println("dimension size:"+list.size());
                System.out.println("variable.getRank:"+variable.getRank());
                for (Dimension dimension:list){
                    System.out.print(dimension.getFullName()+",");
                }
                System.out.println();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static void processNC(String fileName,String outDir){
        try {
            NetcdfFile netcdfFile=NetcdfFile.open(fileName);
            List<Dimension> dimensions = netcdfFile.getDimensions();
            for (Dimension dimension:dimensions){
                System.out.println(dimension.getFullName());
                System.out.println(dimension.getLength());
            }


            System.out.println();
            Variable lat = netcdfFile.findVariable("lat");
            Array lat_data=lat.read();

            lat = netcdfFile.findVariable("lon");
            Array lon_data=lat.read();

            // 0:左上角x坐标 1:东西方向空间分辨率 2:x方向旋转角0° 3:左上角y坐标 4:y方向旋转角0° 5:南北方向空间分辨率
            int size_lon=(int) lon_data.getSize();
            double start_lon=lon_data.getDouble(0);
            double end_lon=lon_data.getDouble(size_lon-1);
            double res_lon=(end_lon-start_lon)/(size_lon-1);

            System.out.println(res_lon);

            int size_lat=(int) lat_data.getSize();
            double start_lat=lat_data.getDouble(0);
            double end_lat=lat_data.getDouble(size_lat-1);
            double res_lat=(end_lat-start_lat)/(size_lat-1);

            System.out.println(res_lat);

            // 0:左上角x坐标 1:东西方向空间分辨率 2:x方向旋转角0° 3:左上角y坐标 4:y方向旋转角0° 5:南北方向空间分辨率
            double[] argin = {start_lon, res_lon, 0, start_lat, 0, res_lat};

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMMddHH");
            LocalDateTime startTime = LocalDateTime.of(1990, 1, 1, 0, 0, 0);

            Variable time=netcdfFile.findVariable("time");
            Variable u=netcdfFile.findVariable("u");
            Variable v=netcdfFile.findVariable("v");
            int[] shp={1,1,(int)lat_data.getSize(),(int)lon_data.getSize()};
            Array timeData=time.read();
            long start=System.currentTimeMillis();
            for (int i=0;i<timeData.getSize();i++){
                int[] origin={i,0,0,0};
                LocalDateTime dtm=startTime.plusHours(timeData.getLong(i));
//                String fileNamePath=outDir+"nwp_cur_"+ formatter.format(dtm) + ".tif";
                String fileNamePath=outDir+"nwp_cur_"+ formatter.format(dtm) + ".shp";
                float[][] u_data=(float[][])u.read(origin,shp).reduce(0).reduce(0).copyToNDJavaArray();
                float[][] v_data=(float[][])v.read(origin,shp).reduce(0).reduce(0).copyToNDJavaArray();

//                writeTif(fileNamePath,argin,u_data,v_data);

//                writeShp(fileNamePath,argin,u_data,v_data,lat_data,lon_data);
               // dumpNCData2(u_data,lat_data,lon_data);//将nc数据处理结果生成的shp至数据库
                dumpNCData(dtm,u_data,v_data,lat_data,lon_data);// 将nc数据处理结果生成的存入数据库
                System.out.println(i+": "+fileNamePath+" finished");
               // break;
            }

            double div=(System.currentTimeMillis()-start)/1000.0;
            System.out.println("耗时:"+div+"秒");

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    //将nc数据处理结果写入到数据库-处理方式2
    private static void dumpNCData(LocalDateTime dtm,float[][] u_data,float[][] v_data,Array lat_data,Array lon_data){
        ArrayList<HashMap> list=new ArrayList<HashMap>();
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = dtm.atZone(zoneId);//Combines this date-time with a time-zone to create a  ZonedDateTime.
        Date date = Date.from(zdt.toInstant());

        java.sql.Date dt=new java.sql.Date(date.getTime());
        Time tm=new java.sql.Time(date.getTime());

        try {
            for (int j = 0; j < u_data.length /*txtArray.length*/; j++) {
                for (int j2 = 0; j2 < u_data[0].length/*txtArray[j].length*/; j2++) {
                    float uu = u_data[j][j2];
                    float vv = v_data[j][j2];
                    if (uu > 100) {

                        continue;
                    }
                    float direction = (float)Utils.getDirection(uu, vv);
                    float speed = (float) Math.sqrt(uu * uu + vv * vv);
                    double lat = lat_data.getDouble(j);
                    double lon = lon_data.getDouble(j2);

                    HashMap map = new HashMap();
                    map.put("dt", dt);
                    map.put("tm", tm);
                    map.put("x", j2);
                    map.put("y", j);
                    map.put("u", direction);
                    map.put("v", speed);
//                    map.put("geom","st_setsrid(st_makepoint("+lon+","+lat+"),4326)");
                    list.add(map);
                }
                if (list.size() >= 20000) {
                    SqlSessionFactoryUtil.dumpPGDatalist(list, "nc_shp_result");
                    list.clear();
                }
            }
            SqlSessionFactoryUtil.dumpPGDatalist(list, "nc_shp_result");
        }catch (Exception e){
                e.printStackTrace();
            }

    }


    //将nc数据处理结果生成的shp至数据库
    private static void dumpNCData2(float[][] u_data,Array lat_data,Array lon_data){
        ArrayList<HashMap> list=new ArrayList<HashMap>();


        try {
            for (int j = 0; j < u_data.length /*txtArray.length*/; j++) {
                for (int j2 = 0; j2 < u_data[0].length/*txtArray[j].length*/; j2++) {

                    double lat = lat_data.getDouble(j);
                    double lon = lon_data.getDouble(j2);

                    HashMap map = new HashMap();
                    map.put("x", j2);
                    map.put("y", j);
                    map.put("lon", lon);
                    map.put("lat", lat);

                    list.add(map);
                    if (list.size() >= 20000) {
                        SqlSessionFactoryUtil.dumpPGDatalist(list, "nc_shp");
                        list.clear();
                    }
                }
            }
            SqlSessionFactoryUtil.dumpPGDatalist(list, "nc_shp");
            list.clear();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    //将nc数据处理到shp文件-处理方式1
    private static void writeShp(String fileNamePath,double[] argin,float[][] u_data,float[][] v_data,Array lat_data,Array lon_data){

        ogr.RegisterAll();
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");//路径中支持中文
        gdal.SetConfigOption("SHAPE_ENCODING", "CP936");// shp属性中支持中文
//        gdal.SetConfigOption("GDAL_DATA","D:\\release-1900-x64-gdal-3-0-2-mapserver-7-4-2\\bin\\gdal-data");

        String strDriverName = "ESRI Shapefile";
        org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
        if (oDriver == null) {
            System.out.println(fileNamePath + " 驱动不可用！\n");
            return;
        }
        DataSource oDS = oDriver.CreateDataSource(fileNamePath, null);
        if (oDS == null) {
            System.out.println("创建矢量文件【" + fileNamePath + "】失败！\n");
            return;
        }



        // 创建图层，创建一个多边形图层，这里没有指定空间参考，如果需要的话，需要在这里进行指定
        //如果是mif或者tab，其实是可以多元素混合存放的，shp每个图层只能存放点线面中的一种。
        //所以tab创建图层的时候，选择什么都不影响后面的操作和存储结果
        SpatialReference spatialReference = new SpatialReference();
        spatialReference.ImportFromEPSG(4326);

        Layer oLayer =oDS.CreateLayer("TestPoint", spatialReference, ogr.wkbPoint, null);
        if (oLayer == null) {
            System.out.println("图层创建失败！\n");
            return;
        }

        // 先创建一个叫FieldID的整型属性
        FieldDefn uFieldID = new FieldDefn("u", ogr.OFTReal);
        oLayer.CreateField(uFieldID, 1);
        FieldDefn vFieldID = new FieldDefn("v", ogr.OFTReal);
        oLayer.CreateField(vFieldID, 1);

        FeatureDefn oDefn = oLayer.GetLayerDefn();

        System.out.println("read finish");


        for (int j = 0; j < u_data.length /*txtArray.length*/; j++) {
            for (int j2 = 0; j2 < u_data[0].length/*txtArray[j].length*/; j2++) {
                float uu=u_data[j][j2];
                float vv=v_data[j][j2];
                if(uu>100){

                    continue;
                }
                double direction=Utils.getDirection(uu,vv);
                double speed =(float) Math.sqrt(uu*uu+vv*vv);
                double lat=lat_data.getDouble(j);
                double lon=lon_data.getDouble(j2);

                Feature oFeatureTriangle = new Feature(oDefn);
                oFeatureTriangle.SetField(0, direction);
                oFeatureTriangle.SetField(1, speed);

                Geometry geomTriangle = Geometry.CreateFromWkt("POINT ("+lon+" "+lat+")");
                oFeatureTriangle.SetGeometry(geomTriangle);
                oLayer.CreateFeature(oFeatureTriangle);
            }
        }


        oDS.SyncToDisk();
        System.out.println("数据集创建完成！");



    }


    private static void writeTif(String fileNamePath,double[] argin,float[][] u_data,float[][] v_data){

        gdal.AllRegister();
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
        //gdal.SetConfigOption("SHAPE_ENCODING","CP936");

        SpatialReference ref = new SpatialReference();
        // 只有这个投影支持输出geotiff OGC WKT   错误参数：WGS84
        ref.SetWellKnownGeogCS("WGS84");
//        ref.SetGeocCS("WGS84");

        String[] defWkt = null;
        ref.ExportToWkt();// 可配置String数组 defWkt
//        if(true)return;
        //驱动名称
        String strDriverName = "GTiff";
        org.gdal.gdal.Driver oDriver = gdal.GetDriverByName(strDriverName);
        if (oDriver == null) {
            System.out.println(strDriverName + " 驱动不可用！\n");
            return;
        }
        // @param数 (name, xsize, ysize, bands, java.lang.String[] options)
        String[] options = null;// 6个参数
        Dataset dataset = oDriver.Create(fileNamePath, u_data[0].length, u_data.length, 2, gdalconst.GDT_Float32);
        // @param double[] argin  地理坐标 米转经纬度单位
        // 0:左上角x坐标 1:东西方向空间分辨率 2:x方向旋转角0° 3:左上角y坐标 4:y方向旋转角0° 5:南北方向空间分辨率
        dataset.SetGeoTransform(argin);
        dataset.SetSpatialRef(ref);
        // @param int xoff(偏移量), int yoff, int xsize, int ysize, int buf_type, byte[] array
        Band v_band = dataset.GetRasterBand(1);// 波段  (色彩)速度v
        Band u_band = dataset.GetRasterBand(2);// 波段  (色彩)方向u
        float[] u = new float[u_data.length*u_data[0].length];
        float[] v = new float[u_data.length*u_data[0].length];
        int c = 0;
        for (int j = 0; j < u_data.length /*txtArray.length*/; j++) {
            for (int j2 = 0; j2 < u_data[0].length/*txtArray[j].length*/; j2++) {
                float uu=u_data[j][j2];
                float vv=v_data[j][j2];
                if(uu>100){
                    u[c]=-99;
                    v[c]=-99;
                    c++;
                    continue;
                }
                double direction=Utils.getDirection(uu,vv);
                u[c]=(float)direction;
                v[c]=(float) Math.sqrt(uu*uu+vv*vv);
                c++;
            }
        }

        // ReadRaster​(int xoff, int yoff, int xsize, int ysize, int buf_type, float[] array)
        // 参数说明： 起始x 起始y x数量(行) y数量(列) 数据类型 数组
        v_band.SetNoDataValue(-99);
        v_band.WriteRaster(0, 0, u_data[0].length, u_data.length, gdalconst.GDT_Float32, v);
        u_band.SetNoDataValue(-99);
        u_band.WriteRaster(0, 0, u_data[0].length, u_data.length, gdalconst.GDT_Float32, u);
        dataset.delete();
        oDriver.delete();

    }


}
